<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div><h1 id="node-js-events-">Node.js Events模块</h1>
<h2 id="labdoc-header-0">一、实验介绍</h2>
<h3 id="labdoc-header-1">1.1 实验内容</h3>
<p>本次实验我们将会学习在Node.js中无处不在的事件(<code>events</code>)，通过本次实验，你将对Node.js的运行机制有所了解。</p><h3 id="labdoc-header-2">1.2 实验知识点</h3>
<ul>
<li>Node.js中事件的概念及其作用</li>
<li><code>events</code>模块中的常用方法</li>
</ul>
<h3 id="labdoc-header-3">1.3 实验环境</h3>
<ul>
<li>Xfce终端</li>
<li>Node.js v4.2.1</li>
<li>gedit/vim：文本编辑</li>
</ul>
<p>在实验1中我们说过，Node.js采用事件驱动模型，在Node.js中，事件是一个很重要的概念。本次实验，我们将学习Node.js事件相关概念及函数。</p><h2 id="labdoc-header-4">二、实验步骤</h2>
<p>很多对象都会发出事件。比如，<code>fs.readStream</code>打开文件时会发出一个事件。所有发出事件的对象都是<code>events.EventEmitter</code>的实例，可以通过<code>require("events");</code>获得<code>event</code>模块。</p><p>通常，事件名采用“驼峰式”(即单词首字母大写，其他字母小写)命名方式，但是，不采用这种命名方式也不会造成程序功能上的问题。但为了程序风格的规范性和一致性，请尽量使用这种命名方式。</p><p>对象发出的事件需要有函数来捕获并处理。为此，需要先使一个事件与一个响应函数建立关系。对象发出事件时，与其建立关系的对应函数就会被执行。这些函数被称作监听器（listeners）。在监听器函数中，<code>this</code>指向发出该事件的<code>EventEmitter</code>对象。</p><h3 id="labdoc-header-5">2.1 events.EventEmitter类</h3>
<p>通过<code>require('events').EventEmitter</code>得到EventEmitter类。</p><p>当EventEmitter对象遇到错误时，通常会触发<code>error</code>事件。<code>error</code>事件在Node.js中是一种特殊情况，如果没有监听器，那么默认会打印出栈跟踪器并退出程序。</p><h3 id="labdoc-header-6">2.2 添加监听器</h3>
<p>为事件绑定事件处理程序，可以使用<code>emitter.addListener(event, listener)</code>和<code>emitter.on(event, listener)</code>，它们的作用是完全一样的。传入的参数是事件（event）和处理函数（listener）。</p><p>在虚拟机桌面新建文件<code>test1.js</code>，输入如下代码并保存：</p><pre><code class="hljs javascript"><span class="hljs-keyword"><span class="hljs-keyword">var</span></span> http = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'http'</span></span>);
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = http.createServer();

<span class="hljs-comment"><span class="hljs-comment">// 为request事件绑定处理函数</span></span>
<span class="hljs-comment"><span class="hljs-comment">// 也可以使用server.addListener</span></span>
server.on(<span class="hljs-string"><span class="hljs-string">'request'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">req, res</span></span></span><span class="hljs-function">) </span></span>{ <span class="hljs-comment"><span class="hljs-comment">//为`request`事件添加一个匿名listener函数</span></span>
    res.writeHead(<span class="hljs-number"><span class="hljs-number">200</span></span>, { <span class="hljs-string"><span class="hljs-string">'Content-Type'</span></span>: <span class="hljs-string"><span class="hljs-string">'text/plain'</span></span> }); <span class="hljs-comment"><span class="hljs-comment">//写入http响应头</span></span>
    res.write(<span class="hljs-string"><span class="hljs-string">'bestqd'</span></span>); <span class="hljs-comment"><span class="hljs-comment">//写入http响应体</span></span>
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'bestqd'</span></span>);
    res.end(); <span class="hljs-comment"><span class="hljs-comment">//结束，返回响应内容</span></span>
});

server.listen(<span class="hljs-number"><span class="hljs-number">1337</span></span>, <span class="hljs-string"><span class="hljs-string">'127.0.0.1'</span></span>); <span class="hljs-comment"><span class="hljs-comment">// 在127.0.0.1(即本地回环)1337端口监听http请求</span></span>
<span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server running at http://127.0.0.1:1337/'</span></span>);
</code></pre><p>运行代码：</p><pre><code class="hljs bash">$ <span class="hljs-built_in">cd</span> Desktop
~/Desktop$ <span class="hljs-keyword">node</span> <span class="hljs-title"><span class="hljs-built_in">test</span>1</span>.js
</code></pre><p>然后打开虚拟机桌面的Firefox浏览器，在地址栏输入127.0.0.1:1337，即可看到页面上打印出了“bestqd”字样，同时console界面也会输出'bestqd'字样。</p><h3 id="labdoc-header-7">2.3 只执行一次的监听器</h3>
<p>使用<code>emitter.once(event, listener)</code>绑定的事件监听器只会执行一次，然后就会被删除掉。</p><p>在虚拟机桌面新建文件<code>test2.js</code>，输入如下代码并保存：</p><pre><code class="hljs javascript"><span class="hljs-keyword"><span class="hljs-keyword">var</span></span> http = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'http'</span></span>);
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = http.createServer();

<span class="hljs-comment"><span class="hljs-comment">// 为request事件绑定处理函数，事件只会执行一次</span></span>
server.once(<span class="hljs-string"><span class="hljs-string">'request'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">req, res</span></span></span><span class="hljs-function">) </span></span>{
    res.writeHead(<span class="hljs-number"><span class="hljs-number">200</span></span>, { <span class="hljs-string"><span class="hljs-string">'Content-Type'</span></span>: <span class="hljs-string"><span class="hljs-string">'text/plain'</span></span> });
    res.write(<span class="hljs-string"><span class="hljs-string">'bestqd'</span></span>);
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'bestqd'</span></span>);
    res.end();
});

server.listen(<span class="hljs-number"><span class="hljs-number">1337</span></span>, <span class="hljs-string"><span class="hljs-string">'127.0.0.1'</span></span>);
<span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server running at http://127.0.0.1:1337/'</span></span>);
</code></pre><p>运行代码：</p><pre><code class="hljs bash">~/Desktop$ <span class="hljs-keyword">node</span> <span class="hljs-title"><span class="hljs-built_in">test</span>2</span>.js
</code></pre><p>打开虚拟机桌面的Firefox浏览器，在地址栏输入127.0.0.1:1337，即可看到页面上打印出了“bestqd”字样，再次刷新此页面，就不会再显示，因为此事件只会执行一次。</p><h3 id="labdoc-header-8">2.4 移除监听器</h3>
<p>移除监听器使用<code>emitter.removeListener(event, listener)</code>。</p><p>在虚拟机桌面新建文件<code>test3.js</code>，输入如下代码并保存：</p><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> http = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'http'</span></span>);
<span class="hljs-keyword">var</span> server = http.createServer();

<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function"> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">callback</span></span></span><span class="hljs-params"><span class="hljs-function">(<span class="hljs-params">req, res</span>)</span></span></span><span class="hljs-function"> </span>{
    res.writeHead(<span class="hljs-number"><span class="hljs-number">200</span></span>, { <span class="hljs-string"><span class="hljs-string">'Content-Type'</span></span>: <span class="hljs-string"><span class="hljs-string">'text/plain'</span></span> });
    res.<span class="hljs-built_in">write</span>(<span class="hljs-string"><span class="hljs-string">'Hello World'</span></span>);
    <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string"><span class="hljs-string">'Hello World'</span></span>);
    res.<span class="hljs-keyword">end</span>();
}

server.on(<span class="hljs-string"><span class="hljs-string">'request'</span></span>, callback);

<span class="hljs-comment">// 移除绑定的监听器callback</span>
server.removeListener(<span class="hljs-string"><span class="hljs-string">'request'</span></span>, callback);

server.on(<span class="hljs-string"><span class="hljs-string">'request'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-params"><span class="hljs-function">(<span class="hljs-params">req, res</span>)</span></span></span><span class="hljs-function"> </span>{
    res.writeHead(<span class="hljs-number"><span class="hljs-number">200</span></span>, { <span class="hljs-string"><span class="hljs-string">'Content-Type'</span></span>: <span class="hljs-string"><span class="hljs-string">'text/plain'</span></span> });
    res.<span class="hljs-built_in">write</span>(<span class="hljs-string"><span class="hljs-string">'bestqd'</span></span>);
    <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string"><span class="hljs-string">'bestqd'</span></span>);
    res.<span class="hljs-keyword">end</span>();
});

server.listen(<span class="hljs-number"><span class="hljs-number">1337</span></span>, <span class="hljs-string"><span class="hljs-string">'127.0.0.1'</span></span>);
<span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string"><span class="hljs-string">'Server running at http://127.0.0.1:1337/'</span></span>);
</code></pre><p>运行代码：</p><pre><code class="hljs bash">~/Desktop$ <span class="hljs-keyword">node</span> <span class="hljs-title"><span class="hljs-built_in">test</span>3</span>.js
</code></pre><p>打开虚拟机桌面的Firefox浏览器，在地址栏输入127.0.0.1:1337，即可看到页面上打印出了“bestqd”字样，为什么没有显示“Hello World”呢？因为显示“Hello World”的监听器被移除了。</p><h3 id="labdoc-header-9">2.5 移除所有监听器</h3>
<p>移除所有监听器使用<code>emitter.removeAllListeners([event])</code>。</p><p>在虚拟机桌面新建文件<code>test4.js</code>，输入如下代码并保存：</p><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> http = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'http'</span></span>);
<span class="hljs-keyword">var</span> server = http.createServer();

server.on(<span class="hljs-string"><span class="hljs-string">'request'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-params"><span class="hljs-function">(<span class="hljs-params">req, res</span>)</span></span></span><span class="hljs-function"> </span>{
    res.writeHead(<span class="hljs-number"><span class="hljs-number">200</span></span>, { <span class="hljs-string"><span class="hljs-string">'Content-Type'</span></span>: <span class="hljs-string"><span class="hljs-string">'text/plain'</span></span> });
    res.<span class="hljs-built_in">write</span>(<span class="hljs-string"><span class="hljs-string">'bestqd,111'</span></span>);
    <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string"><span class="hljs-string">'bestqd,111'</span></span>);
    res.<span class="hljs-keyword">end</span>();
});

server.on(<span class="hljs-string"><span class="hljs-string">'request'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-params"><span class="hljs-function">(<span class="hljs-params">req, res</span>)</span></span></span><span class="hljs-function"> </span>{
    res.writeHead(<span class="hljs-number"><span class="hljs-number">200</span></span>, { <span class="hljs-string"><span class="hljs-string">'Content-Type'</span></span>: <span class="hljs-string"><span class="hljs-string">'text/plain'</span></span> });
    res.<span class="hljs-built_in">write</span>(<span class="hljs-string"><span class="hljs-string">'bestqd,222'</span></span>);
    <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string"><span class="hljs-string">'bestqd,222'</span></span>);
    res.<span class="hljs-keyword">end</span>();
});

<span class="hljs-comment">// 移除绑定的所有监听器</span>
server.removeAllListeners(<span class="hljs-string"><span class="hljs-string">'request'</span></span>);

server.on(<span class="hljs-string"><span class="hljs-string">'request'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-params"><span class="hljs-function">(<span class="hljs-params">req, res</span>)</span></span></span><span class="hljs-function"> </span>{
    res.writeHead(<span class="hljs-number"><span class="hljs-number">200</span></span>, { <span class="hljs-string"><span class="hljs-string">'Content-Type'</span></span>: <span class="hljs-string"><span class="hljs-string">'text/plain'</span></span> });
    res.<span class="hljs-built_in">write</span>(<span class="hljs-string"><span class="hljs-string">'bestqd'</span></span>);
    <span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string"><span class="hljs-string">'bestqd'</span></span>);
    res.<span class="hljs-keyword">end</span>();
});

server.listen(<span class="hljs-number"><span class="hljs-number">1337</span></span>, <span class="hljs-string"><span class="hljs-string">'127.0.0.1'</span></span>);
<span class="hljs-built_in">console</span>.<span class="hljs-built_in">log</span>(<span class="hljs-string"><span class="hljs-string">'Server running at http://127.0.0.1:1337/'</span></span>);
</code></pre><p>运行代码：</p><pre><code class="hljs bash">~/Desktop$ <span class="hljs-keyword">node</span> <span class="hljs-title"><span class="hljs-built_in">test</span>4</span>.js
</code></pre><p>打开虚拟机桌面的Firefox浏览器，在地址栏输入127.0.0.1:1337，即可看到页面上打印出了“bestqd”字样，说明前面的监听器被移除了，都没有执行，所以没有显示，同时console界面也只会输出'bestqd'字样。</p><h3 id="labdoc-header-10">2.6 设置监听器最大绑定数</h3>
<p><code>emitter.setMaxListeners(n)</code>可以设置同一事件的监听器最大绑定数，默认情况下，超过10个就会警告提示，这能帮我们快速找到内存泄露的地方。显然，不是所有的事件触发器都限制在10个监听器，通过这个方法可以设置，如果设置为0就是无限制。</p><h3 id="labdoc-header-11">2.7 自定义事件</h3>
<p>使用<code>emitter.emit(event, [arg1], [arg2], [...])</code>可以触发自定义的事件。</p><p>在虚拟机桌面新建文件<code>test5.js</code>，输入如下代码并保存：</p><pre><code class="hljs javascript"><span class="hljs-keyword"><span class="hljs-keyword">var</span></span> http = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'http'</span></span>);
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = http.createServer();

<span class="hljs-comment"><span class="hljs-comment">// 绑定自定义事件myevent</span></span>
server.on(<span class="hljs-string"><span class="hljs-string">'myevent'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">arg</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(arg);
});

<span class="hljs-comment"><span class="hljs-comment">// 触发自定义事件</span></span>
server.emit(<span class="hljs-string"><span class="hljs-string">'myevent'</span></span>, <span class="hljs-string"><span class="hljs-string">'bestqd'</span></span>);

server.listen(<span class="hljs-number"><span class="hljs-number">1337</span></span>, <span class="hljs-string"><span class="hljs-string">'127.0.0.1'</span></span>);
<span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server running at http://127.0.0.1:1337/'</span></span>);
</code></pre><p>运行代码：</p><pre><code class="hljs bash">~/Desktop$ <span class="hljs-keyword">node</span> <span class="hljs-title"><span class="hljs-built_in">test</span>5</span>.js
</code></pre><p>可以看到console界面输出了'bestqd'字样，说明触发自定义事件成功。</p><h3 id="labdoc-header-12">2.8 查看事件绑定的监听器个数</h3>
<p>使用<code>EventEmitter.listenerCount(emitter, event)</code>可以查看事件监听器数量。</p><p>在虚拟机桌面新建文件<code>test6.js</code>，输入如下代码并保存：</p><pre><code class="hljs javascript"><span class="hljs-keyword"><span class="hljs-keyword">var</span></span> http = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'http'</span></span>);
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> events = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'events'</span></span>); <span class="hljs-comment"><span class="hljs-comment">// 加载events模块</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = http.createServer();

server.on(<span class="hljs-string"><span class="hljs-string">'request'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">req, res</span></span></span><span class="hljs-function">) </span></span>{
    res.writeHead(<span class="hljs-number"><span class="hljs-number">200</span></span>, { <span class="hljs-string"><span class="hljs-string">'Content-Type'</span></span>: <span class="hljs-string"><span class="hljs-string">'text/plain'</span></span> });
    res.write(<span class="hljs-string"><span class="hljs-string">'bestqd,111'</span></span>);
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'bestqd,111'</span></span>);
});

server.on(<span class="hljs-string"><span class="hljs-string">'request'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">req, res</span></span></span><span class="hljs-function">) </span></span>{
    res.write(<span class="hljs-string"><span class="hljs-string">'\nbestqd,222'</span></span>);
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'bestqd,222'</span></span>);
    res.end();
});

server.listen(<span class="hljs-number"><span class="hljs-number">1337</span></span>, <span class="hljs-string"><span class="hljs-string">'127.0.0.1'</span></span>);
<span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server running at http://127.0.0.1:1337/'</span></span>);

<span class="hljs-comment"><span class="hljs-comment">// 查看server绑定的'request'事件的监听器个数</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> num = events.EventEmitter.listenerCount(server, <span class="hljs-string"><span class="hljs-string">'request'</span></span>);
<span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(num);
</code></pre><p>运行代码：</p><pre><code class="hljs bash">~/Desktop$ <span class="hljs-keyword">node</span> <span class="hljs-title"><span class="hljs-built_in">test</span>6</span>.js
</code></pre><p>可以看到console界面输出了数字“2”，因为server绑定了两个监听器到'request'事件。</p><h2 id="labdoc-header-13">三、实验总结</h2>
<ol>
<li>Node.js 中所有能发出事件的对象都是events.EventEmitter的实例，对象发出事件后，需要有响应函数进行响应处理。</li>
<li>EventEmitter类的对象具有一系列方法可以进行事件相关操作，他们是：</li>
</ol>
<ul>
<li>addListener(event,listener) / on(event,listener): 为对象的事件event添加监听器listener.</li>
<li>once(evnet,listener): 为对象的事件event添加只响应一次的监听器listener.</li>
<li>removeListener(event,listener): 移除一个监听器listener.</li>
<li>removeAllListeners([listeners]): 移除与一个对象绑定的所有listener.</li>
<li>setMaxListeners(n): 设置与一个对象绑定的监听器最多有n个。</li>
<li>emit(event, [arg1], [arg2], [...]): 触发事件event.</li>
<li>listenerCount(): 查看与对象绑定的监听器的个数。</li>
</ul>
<h2 id="labdoc-header-14">四、课后习题</h2>
<p>事件模块涉及的函数方法较多，请你自行练习，掌握它们的使用方法。</p></div>
</body>
</html>